﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Microsoft.SharePoint;

namespace SPMetadataSecurity
{
    public class MetadataSecurityEventReceiver : SPItemEventReceiver
    {
        public override void ItemAdded(SPItemEventProperties properties)
        {
            try
            {
                this.EventFiringEnabled = false;                
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    MetadataSecuirtyConfiguration config = GetSecurityConfiguration(properties);
                    if (config != null)
                    {
                        ApplySecuritySettings(properties, config);
                    }
                });
            }
            catch (Exception ex)
            {                
                throw ex;
            }
            finally
            {
                this.EventFiringEnabled = true;
            }            
        }

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            try
            {
                this.EventFiringEnabled = false;
                SPSecurity.RunWithElevatedPrivileges(delegate()
                {
                    MetadataSecuirtyConfiguration config = GetSecurityConfiguration(properties);
                    if (config != null)
                    {
                        ApplySecuritySettings(properties, config);
                    }
                });
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                this.EventFiringEnabled = true;
            }  
        }
        private void ApplySecuritySettings(SPItemEventProperties properties, MetadataSecuirtyConfiguration config)
        {
            SPListItem currentItem = properties.ListItem;
            SPWeb rootWeb = properties.Site.RootWeb;            
            if(config.ConfigurationRules != null && config.ConfigurationRules.Count > 0)
            {
                foreach(Rule rule in config.ConfigurationRules)
                {
                    bool conditionsMatch = true;
                    if (rule != null && rule.Conditions != null && rule.Conditions.Count > 0)
                    {
                        foreach (Condition condition in rule.Conditions)
                        {
                            SPField field = currentItem.Fields.GetField(condition.MetadataColumnName);
                            switch(field.Type)
                            {
                                case SPFieldType.Text:
                                    if (currentItem[new Guid(condition.MetadataColumnId)].ToString() != condition.MetadataValue.ToString())
                                    {
                                        conditionsMatch = false;
                                    }
                                    break;
                                case SPFieldType.Number:
                                    if (currentItem[new Guid(condition.MetadataColumnId)].ToString() != condition.MetadataValue.ToString())
                                    {
                                        conditionsMatch = false;
                                    }
                                    break;
                                case SPFieldType.Boolean:
                                    if (currentItem[new Guid(condition.MetadataColumnId)].ToString().ToLower() != condition.MetadataValue.ToString().ToLower())
                                    {
                                        conditionsMatch = false;
                                    }
                                    break;
                            }
                            
                        }                        
                    }
                    if (conditionsMatch)
                    {
                        if (rule.Action != null)
                        {
                            var action = rule.Action;
                            if (action.StopInheritingPermission)
                            {
                                currentItem.BreakRoleInheritance(!action.RemoveInheritedPermissions);
                            }
                            if (action.UpdateExistingItems)
                            {
                                // TBD
                            }
                            if (action.GroupPermissions != null && action.GroupPermissions.Count > 0)
                            {
                                foreach (GroupPermission gp in action.GroupPermissions)
                                {
                                    var roleDef = rootWeb.RoleDefinitions[gp.PermissionLevelName];
                                    var group = rootWeb.Groups[gp.GroupName];
                                    var roleAssignment = new SPRoleAssignment(group);
                                    roleAssignment.RoleDefinitionBindings.Add(roleDef);
                                    currentItem.RoleAssignments.Add(roleAssignment);
                                    currentItem.Update();
                                }
                            }
                        }
                        if (rule.StopIfRuleApplies)
                        {
                            break;
                        }
                    }                    
                }
            }
        }
        private MetadataSecuirtyConfiguration GetSecurityConfiguration(SPItemEventProperties properties)
        {
            SPContentType contentType = properties.ListItem.ContentType;
            SPWeb rootWeb = properties.Site.RootWeb;
            string xml = rootWeb.GetProperty(contentType.Name + "_Metadata_Security") as string;
            MetadataSecuirtyConfiguration config = null;
            if (!string.IsNullOrEmpty(xml))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(MetadataSecuirtyConfiguration));
                StringReader reader = new StringReader(xml);
                config = serializer.Deserialize(reader) as MetadataSecuirtyConfiguration;
            }
            return config;
        }
    }
}
